class ZombieGoreallyFast extends ZombieGoreFast_Base;

#exec OBJ LOAD FILE=SimHostOrgTex.utx

simulated function PostNetReceive()
{
	if (bRunning)
		MovementAnims[0]='ZombieRun';
	else MovementAnims[0]=default.MovementAnims[0];
}

// This zed has been taken control of. Boost its health and speed
function SetMindControlled(bool bNewMindControlled)
{
	if( bNewMindControlled )
	{
		NumZCDHits++;

		// if we hit him a couple of times, make him rage!
		if( NumZCDHits > 1 )
		{
			if( !IsInState('RunningToMarker') )
			{
				GotoState('RunningToMarker');
			}
			else
			{
				NumZCDHits = 1;
				if( IsInState('RunningToMarker') )
				{
					GotoState('');
				}
			}
		}
		else
		{
			if( IsInState('RunningToMarker') )
			{
				GotoState('');
			}
		}

		if( bNewMindControlled != bZedUnderControl )
		{
			GroundSpeed = OriginalGroundSpeed * 1.25;
			Health *= 1.25;
			HealthMax *= 1.25;
		}
	}
	else
	{
		NumZCDHits=0;
	}

	bZedUnderControl = bNewMindControlled;
}

// Handle the zed being commanded to move to a new location
function GivenNewMarker()
{
	if( bRunning && NumZCDHits > 1 )
	{
		GotoState('RunningToMarker');
	}
	else
	{
		GotoState('');
	}
}

//charge from farther away
function RangedAttack(Actor A)
{
	Super.RangedAttack(A);
	if( !bShotAnim && !bDecapitated && VSize(A.Location-Location)<=1400 )
		GoToState('RunningState');
}

state RunningState
{
	// Don't override speed in this state
	function bool CanSpeedAdjust()
	{
		return false;
	}

	function BeginState()
	{
		GroundSpeed = OriginalGroundSpeed * 1.875;
		bRunning = true;
		if( Level.NetMode!=NM_DedicatedServer )
			PostNetReceive();
		NetUpdateTime = Level.TimeSeconds - 1;
	}

	function EndState()
	{
		GroundSpeed = GetOriginalGroundSpeed();
		bRunning = false;
		if( Level.NetMode!=NM_DedicatedServer )
			PostNetReceive();

		RunAttackTimeout=0;
		NetUpdateTime = Level.TimeSeconds - 1;
	}

	function RemoveHead()
	{
		GoToState('');
		Global.RemoveHead();
	}

	function RangedAttack(Actor A)
	{
		local float ChargeChance;

		// Decide what chance the gorefast has of charging during an attack
		if( Level.Game.GameDifficulty < 2.0 )
		{
			ChargeChance = 0.1;
		}
		else if( Level.Game.GameDifficulty < 4.0 )
		{
			ChargeChance = 0.2;
		}
		else if( Level.Game.GameDifficulty < 5.0 )
		{
			ChargeChance = 0.3;
		}
		else // Hardest difficulty
		{
			ChargeChance = 0.4;
		}

		if ( bShotAnim || Physics == PHYS_Swimming)
			return;
		else if ( CanAttack(A) )
		{
			bShotAnim = true;

			// Randomly do a moving attack so the player can't kite the zed
			if( FRand() < ChargeChance )
			{
				SetAnimAction('ClawAndMove');
				RunAttackTimeout = GetAnimDuration('GoreAttack1', 1.0);
			}
			else
			{
				SetAnimAction('Claw');
				Controller.bPreparingMove = true;
				Acceleration = vect(0,0,0);
				// Once we attack stop running
				GoToState('');
			}
			return;
		}
	}

	simulated function Tick(float DeltaTime)
	{
		// Keep moving toward the target until the timer runs out (anim finishes)
		if( RunAttackTimeout > 0 )
		{
			RunAttackTimeout -= DeltaTime;

			if( RunAttackTimeout <= 0 && !bZedUnderControl )
			{
				RunAttackTimeout = 0;
				GoToState('');
			}
		}

		// Keep the gorefast moving toward its target when attacking
		if( Role == ROLE_Authority && bShotAnim && !bWaitForAnim )
		{
			if( LookTarget!=None )
			{
				Acceleration = AccelRate * Normal(LookTarget.Location - Location);
			}
		}

		Global.Tick(DeltaTime);
	}


Begin:
	GoTo('CheckCharge');
CheckCharge:
	if( Controller!=None && Controller.Target!=None && VSize(Controller.Target.Location-Location)<700 )
	{
		Sleep(0.5+ FRand() * 0.5);
		//log("Still charging");
		GoTo('CheckCharge');
	}
	else
	{
		//log("Done charging");
		GoToState('');
	}
}

// State where the zed is charging to a marked location.
state RunningToMarker extends RunningState
{
	simulated function Tick(float DeltaTime)
	{
		// Keep moving toward the target until the timer runs out (anim finishes)
		if( RunAttackTimeout > 0 )
		{
			RunAttackTimeout -= DeltaTime;

			if( RunAttackTimeout <= 0 && !bZedUnderControl )
			{
				RunAttackTimeout = 0;
				GoToState('');
			}
		}

		// Keep the gorefast moving toward its target when attacking
		if( Role == ROLE_Authority && bShotAnim && !bWaitForAnim )
		{
			if( LookTarget!=None )
			{
				Acceleration = AccelRate * Normal(LookTarget.Location - Location);
			}
		}

		Global.Tick(DeltaTime);
	}


Begin:
	GoTo('CheckCharge');
CheckCharge:
	if( bZedUnderControl || (Controller!=None && Controller.Target!=None && VSize(Controller.Target.Location-Location)<700) )
	{
		Sleep(0.5+ FRand() * 0.5);
		GoTo('CheckCharge');
	}
	else
	{
		GoToState('');
	}
}

// Overridden to handle playing upper body only attacks when moving
simulated event SetAnimAction(name NewAction)
{
	local int meleeAnimIndex;
	local bool bWantsToAttackAndMove;

	if( NewAction=='' )
		return;

	bWantsToAttackAndMove = NewAction == 'ClawAndMove';

	if( NewAction == 'Claw' )
	{
		meleeAnimIndex = Rand(3);
		NewAction = meleeAnims[meleeAnimIndex];
		CurrentDamtype = ZombieDamType[meleeAnimIndex];
	}

	if( bWantsToAttackAndMove )
	{
		ExpectingChannel = AttackAndMoveDoAnimAction(NewAction);
	}
	else
	{
		ExpectingChannel = DoAnimAction(NewAction);
	}

	if( !bWantsToAttackAndMove && AnimNeedsWait(NewAction) )
	{
		bWaitForAnim = true;
	}
	else
	{
		bWaitForAnim = false;
	}

	if( Level.NetMode!=NM_Client )
	{
		AnimAction = NewAction;
		bResetAnimAct = True;
		ResetAnimActTime = Level.TimeSeconds + 0.3;
	}
}

// Handle playing the anim action on the upper body only if we're attacking and moving
simulated function int AttackAndMoveDoAnimAction( name AnimName )
{
	local int meleeAnimIndex;

	if( AnimName == 'ClawAndMove' )
	{
		meleeAnimIndex = Rand(3);
		AnimName = meleeAnims[meleeAnimIndex];
		CurrentDamtype = ZombieDamType[meleeAnimIndex];
	}

	if( AnimName=='GoreAttack1' || AnimName=='GoreAttack2' )
	{
		AnimBlendParams(1, 1.0, 0.0,, FireRootBone);
		PlayAnim(AnimName,, 0.1, 1);
		return 1;
	}

	return Super.DoAnimAction( AnimName );
}

simulated function HideBone(name boneName)
{
	local int BoneScaleSlot;
	local coords boneCoords;
	local bool bValidBoneToHide;

	if( boneName == LeftThighBone )
	{
		boneScaleSlot = 0;
		bValidBoneToHide = true;
		if( SeveredLeftLeg == none )
		{
			SeveredLeftLeg = Spawn(SeveredLegAttachClass,self);
			SeveredLeftLeg.SetDrawScale(SeveredLegAttachScale);
			boneCoords = GetBoneCoords( 'lleg' );
			AttachEmitterEffect( LimbSpurtEmitterClass, 'lleg', boneCoords.Origin, rot(0,0,0) );
			AttachToBone(SeveredLeftLeg, 'lleg');
		}
	}
	else if ( boneName == RightThighBone )
	{
		boneScaleSlot = 1;
		bValidBoneToHide = true;
		if( SeveredRightLeg == none )
		{
			SeveredRightLeg = Spawn(SeveredLegAttachClass,self);
			SeveredRightLeg.SetDrawScale(SeveredLegAttachScale);
			boneCoords = GetBoneCoords( 'rleg' );
			AttachEmitterEffect( LimbSpurtEmitterClass, 'rleg', boneCoords.Origin, rot(0,0,0) );
			AttachToBone(SeveredRightLeg, 'rleg');
		}
	}
	else if( boneName == RightFArmBone )
	{
		boneScaleSlot = 2;
		bValidBoneToHide = true;
		if( SeveredRightArm == none )
		{
			SeveredRightArm = Spawn(SeveredArmAttachClass,self);
			SeveredRightArm.SetDrawScale(SeveredArmAttachScale);
			boneCoords = GetBoneCoords( 'rarm' );
			AttachEmitterEffect( LimbSpurtEmitterClass, 'rarm', boneCoords.Origin, rot(0,0,0) );
			AttachToBone(SeveredRightArm, 'rarm');
		}
	}
	else if ( boneName == LeftFArmBone )
	{
		// No LeftArm
		return;
	}
	else if ( boneName == HeadBone )
	{
		// Only scale the bone down once
		if( SeveredHead == none )
		{
			bValidBoneToHide = true;
			boneScaleSlot = 4;
			SeveredHead = Spawn(SeveredHeadAttachClass,self);
			SeveredHead.SetDrawScale(SeveredHeadAttachScale);
			boneCoords = GetBoneCoords( 'neck' );
			AttachEmitterEffect( NeckSpurtEmitterClass, 'neck', boneCoords.Origin, rot(0,0,0) );
			AttachToBone(SeveredHead, 'neck');
		}
		else
		{
			return;
		}
	}
	else if ( boneName == 'spine' )
	{
		bValidBoneToHide = true;
		boneScaleSlot = 5;
	}

	// Only hide the bone if it is one of the arms, legs, or head, don't hide other misc bones
	if( bValidBoneToHide )
	{
		SetBoneScale(BoneScaleSlot, 0.0, BoneName);
	}
}

defaultproperties
{
	DetachedArmClass=Class'KFChar.SeveredArmGorefast'
	DetachedLegClass=Class'KFChar.SeveredLegGorefast'
	DetachedHeadClass=Class'KFChar.SeveredHeadGorefast'
	ControllerClass=Class'PerksSimHostOrg.GorefastController'
	GroundSpeed=160.000000
	WaterSpeed=100.000000
	MenuName="Goreallyfast"
	Skins(0)=Texture'SimHostOrgTex.WTFZombies.Goreallyfast'
}